using System;
using System.Collections;
using System.Collections.Generic;
using Framework.Library.Core.Utils.Miscellaneous;

namespace Framework.Library.Core.Utils.Collections
{
    public static class EnumerableUtils
    {
        /// <summary>
        /// Performs an action for each item in an enumerable, divided by a seperator action.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumerable">The enumerable.</param>
        /// <param name="action">The action.</param>
        /// <param name="seperatorAction">The seperator action.</param>
        public static void ForEach<T>(IEnumerable<T> enumerable, Action<T> action, Action<T> seperatorAction)
        {
            ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
            ValidationUtils.ArgumentNotNull(action, "action");

            bool first = true;

            foreach (T item in enumerable)
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    if (seperatorAction != null)
                        seperatorAction(item);
                }

                action(item);
            }
        }

        /// <summary>
        /// Creates an enumerable from a creator with the specified count.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="itemCreator">The item creator.</param>
        /// <param name="count">The count.</param>
        /// <returns></returns>
        public static IEnumerable<T> Create<T>(Creator<T> itemCreator, int count)
        {
            ValidationUtils.ArgumentNotNull(itemCreator, "itemCreator");
            ValidationUtils.ArgumentNotNegative<int>(count, "count");

            for (int i = 0; i < count; i++)
            {
                yield return itemCreator();
            }
        }

        public static IEnumerable<int> Times(int times)
        {
            for (int i = 1; i <= times; i++)
            {
                yield return i;
            }
        }

        public static IEnumerable<T> Convert<T>(IEnumerable enumerable)
        {
            return Convert<T>(enumerable, false);
        }

        public static IEnumerable<T> Convert<T>(IEnumerable enumerable, bool defaultOnBadType)
        {
            ValidationUtils.ArgumentNotNull(enumerable, "enumerable");

            return new EnumerableWrapper<T>(enumerable, defaultOnBadType, true);
        }

        public static string ToString(IEnumerable enumerable)
        {
            return ToString(enumerable, delegate(object value) { return MiscellaneousUtils.ToString(value); }, ", ");
        }

        public static string ToString(IEnumerable enumerable, Converter<object, string> converter)
        {
            return ToString(enumerable, converter, ", ");
        }

        public static string ToString(IEnumerable enumerable, Converter<object, string> converter, string separator)
        {
            ValidationUtils.ArgumentNotNull(enumerable, "enumerable");

            return ToString(Convert<object>(enumerable), converter, separator);
        }

        public static string ToString<T>(IEnumerable<T> collection, Converter<T, string> converter)
        {
            return ToString(Convert<T>(collection), converter, ", ");
        }

        public static string ToString<T>(IEnumerable<T> enumerable, Converter<T, string> converter, string separator)
        {
            ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
            ValidationUtils.ArgumentNotNull(converter, "converter");
            ValidationUtils.ArgumentNotNull(separator, "separator");

            var list = new List<T>(enumerable);

            List<string> texts = list.ConvertAll(converter);

            return string.Join(separator, texts.ToArray());
        }
    }
}